/*
* This is an expamle server for the lcpd-scope Project. It starts a server on Port 1234 and waits for incomming connections.
* It can be used as an template for more complicated Interfaces to A/D-converters
*
* @author kurmt1@bfh.ch, woodr1@bfh.ch, eichs2@bfh.ch
* @version 1.0
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h> 
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <pthread.h>
#include <fcntl.h>

enum Commands
{
	Read,
	SetFullscale,
	SetSamplingRate,
	SetTriggerLevel,
	SetTriggerChannel,
	SetTriggerMode,
	SetChannelActive,
	SetProbeMultiplier,
	DataMode,
	SystemOK,
	Close
};

#define PORT 1234
#define RETURN_OK 0
#define RETURN_FAIL 1
#define DATALEN 4000
#define AandB 0
#define Aonly 1
#define Bonly 2
#define CHANNEL_NUMBER 2

#define DEVICE_NAME "/dev/lcpd-scope"

void error(char *msg)
{
	perror(msg);
	exit(1);
}
typedef enum {Normal,Auto,Roll,SingleSlope}LCPDTriggerMode;
typedef enum {negative,positive}LCPDTriggerEdge;
typedef struct {
	float MaxVoltage[CHANNEL_NUMBER];
	char CouplingMode[CHANNEL_NUMBER];
	float TotalTime;
	float DisplayTime;
	float BufferSize;
	float TriggerLevel;
	LCPDTriggerMode TriggerMode;
	LCPDTriggerEdge TriggerEdge;
}typeReceiveData;

typedef struct {
	float* SamplingData;
	float SamplingRate;

}typeSendData;

typeReceiveData ReceiveData;
typeSendData SendData;
float ChannelDataBuffer[CHANNEL_NUMBER][DATALEN];
char newData;
unsigned short DataBuffer[DATALEN];
char clearDevice=0;
pthread_mutex_t MutexLock;

void getSamples();
void Communication();

float ByteToFloat (unsigned char *Buffer)
{
	return *((float*)Buffer);
}

int ByteToInt (char *Buffer)
{
	return (int) *Buffer;
}

int main(int argc, char *argv[])
{
    pthread_t thread1, thread2;
    int i, rc;

    SendData.SamplingData=ChannelDataBuffer;
    newData=0;
    pthread_mutex_init(&MutexLock, NULL);
    rc = pthread_create( &thread1, NULL, &Communication, NULL );
    if( rc != 0 ) {
        printf("Konnte Thread 1 nicht erzeugen\n");
        return EXIT_FAILURE;
    }
    // Thread 2 erzeugen
    rc = pthread_create( &thread2, NULL, &getSamples, NULL );
    if( rc != 0 ) {
        printf("Konnte Thread 2 nicht erzeugen\n");
        return EXIT_FAILURE;
    }
    // Main-Thread wartet auf beide Threads.
    pthread_join( thread1, NULL );
    pthread_join( thread2, NULL );
	//	lcpdfile = open(DEVICE_NAME, 0);
	//	if(lcpdfile < 0) error("ERROR opening Driver!");



}
/*
 * This is the communication Thread, it waits for some connection, recives commands and sends the sampling data
 *
 */
void Communication()
{
	int sockfd, newsockfd, clilen;
	unsigned char CommandBuffer[30];
	unsigned int RawDataBuffer[DATALEN];
	struct sockaddr_in serv_addr, cli_addr;
	int n, ConnectionOpen = 0;
	int lcpdfile, ret_val;
	volatile int ChannelAactive = 1;
	volatile int ChannelBactive = 1;
	char retvalue[2];
	int i,j,t;
	int nData = 0;

	printf("Communication Thread: started\n");
	sockfd = socket(AF_INET, SOCK_STREAM, 0);
	if (sockfd < 0)
		error("ERROR opening socket\n");
	bzero((char *) &serv_addr, sizeof(serv_addr));

	serv_addr.sin_family = AF_INET;
	serv_addr.sin_addr.s_addr = INADDR_ANY;
	serv_addr.sin_port = htons(PORT);
	if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
		error("ERROR on binding\n");

	listen(sockfd, 5);
	clilen = sizeof(cli_addr);
	printf("Waiting for Connection \n");

	while (1)
	{
		newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen); // Wait for connection
		if (newsockfd < 0)
			error("ERROR on accept\n");

		ConnectionOpen = 1;
		printf("Connected to %s \n", inet_ntoa(cli_addr.sin_addr));

		while (ConnectionOpen)
		{
			//printf("Waiting for Command \n");
			n = read(newsockfd, CommandBuffer, 30);
			if (n==0)
			{
				ConnectionOpen=0;
			}
			else if (n==2)
			{
				if (CommandBuffer[0]==67&&CommandBuffer[1]==1)
				{
					while (newData==0) usleep(100000);
					n = send(newsockfd, ((char*)&SendData.SamplingRate), 4*sizeof(char),0);
					for(t=0;t<CHANNEL_NUMBER;t++)
					{
						n = send(newsockfd, (char*)(SendData.SamplingData+t*(int)ReceiveData.BufferSize), ReceiveData.BufferSize
								* 4 *sizeof(char),MSG_DONTWAIT);
					}
					newData=0;
				}
			}
			else
			{
				if (CommandBuffer[0]==67)
				{
					i=1;
					for (j=0;j<CHANNEL_NUMBER;j++)
					{
						ReceiveData.MaxVoltage[j]=ByteToFloat(&CommandBuffer[i]);
						i+=4;
						ReceiveData.CouplingMode[j]=CommandBuffer[i];
						i++;
					}
					ReceiveData.TotalTime=ByteToFloat(&CommandBuffer[i]);
					i+=4;
					ReceiveData.DisplayTime=ByteToFloat(&CommandBuffer[i]);
					i+=4;
					ReceiveData.BufferSize=ByteToFloat(&CommandBuffer[i]);
					i+=4;
					ReceiveData.TriggerLevel=ByteToFloat(&CommandBuffer[i]);
					i+=4;
					ReceiveData.TriggerMode=CommandBuffer[i];
					i++;
					ReceiveData.TriggerEdge=CommandBuffer[i];
					i++;
					//pthread_mutex_lock (&MutexLock);
//					printf("Clear Device");
//					clearDevice=1;
//					newData=0;
					//pthread_mutex_unlock (&MutexLock);
					// if readout
					if (CommandBuffer[i]==1)
					{
						//pthread_mutex_lock (&MutexLock);
						while (newData==0) {
							//pthread_mutex_unlock (&MutexLock);
							usleep(100000);
							//pthread_mutex_lock (&MutexLock);
						}
						//pthread_mutex_lock (&MutexLock);
						n = send(newsockfd, ((char*)&SendData.SamplingRate), 4*sizeof(char),0);
						for(t=0;t<CHANNEL_NUMBER;t++)
						{
							n = send(newsockfd, (char*)(SendData.SamplingData+t*(int)ReceiveData.BufferSize), ReceiveData.BufferSize
									* 4 *sizeof(char),MSG_DONTWAIT);
						}
						newData=0;
						//pthread_mutex_unlock (&MutexLock);
					}
				}
				printf("Command Received \n");
			}
		}
	}
	printf("Communication Thread: stopped\n");
	close(lcpdfile);
	pthread_exit((void*) 0);
}

/*
 * This is the Datat acquisition thread, it trys to read data from the
 * /dev/dsp interface which is the sound card of linux
 */
void getSamples()
{
	int j,t;
	int dsp;

	if((dsp=open("/dev/dsp", O_RDONLY))==-1) {
	  perror("Error: open(/dev/dsp)\n");
	  //return EXIT_FAILURE;
	}
	//printf("Buffer size:%i",ReceiveData.BufferSize);
	printf("Sample Thread: started\n");
	while (1)
	{
		//pthread_mutex_lock (&MutexLock);
		if (newData==0)
		{
			if (clearDevice)
			{
				fflush(dsp);
				clearDevice=0;
			}
			printf("Sample Thread read: %i",read(dsp, DataBuffer, ReceiveData.BufferSize*sizeof(short)));
			for(j=0;j<ReceiveData.BufferSize;j++)
			{
				SendData.SamplingData[j]=(float)5.0/65535.0*(DataBuffer[j]-32768.0);
			}
			SendData.SamplingRate=44000;
			newData=1;
		}
		usleep(10000);
		//pthread_mutex_unlock (&MutexLock);
	}
	printf("Sample Thread: stopped\n");
	pthread_exit((void*) 0);
	close (dsp);
	//usleep(1000000/ReceiveData.BufferSize);
	return 0;
}
